/******************************************************************************
 * Author:      671643387
 * Created:     2016/9/30
 *****************************************************************************/
var mUtil = require('./util.js');
var ErrorCodes = require('./error.js').ErrorCodes;
var LaomaziPlayer = require('./player.js').Player;
var mFunc = require('./function.js');
var subGame = require('./sub/index.js');
var mjMark = require('./mjmark.js');

var ROOMMAXPALYER = 3;
///////////////////////////////////////////////////////////////////////////////

/**
 * 扑克牌
 * @constructor
 */
function roomPokers(owner) {
    this.pokers = [];
    this.owner = owner;
}
roomPokers.prototype = {
    /**
     * 生成扑克
     * @param category
     */
    gen: function(category) {
        this.pokers = mUtil.genLaomazi(category);
    },

    /**
     * 摸牌
     * @param room
     * @param num
     * @returns {Array}
     */
    dealCards: function(num) {
        var room = this.owner;

        var cards = [];
        for (var i = 0; i < num; ++i) {
            cards.push(this.pokers[room.roundInfo.dealIndex]);
            room.roundInfo.dealIndex += 1;
            if (room.roundInfo.dealIndex >= 48) {
                break;
            }
        }
        return cards;
    },
};

/**
 * 已经出的牌
 * @constructor
 */
function DealedPoker(owner) {
    this.pokers = [];
    this.owner = owner;
}
DealedPoker.prototype = {
    add: function(card, owner) {
        card.owner = owner;
        this.pokers.push(card);
    },

    find: function (owner, Card) {
        var numCard = 0;
        this.pokers.forEach(function (card) {
            if(card.owner == owner && card.value == Card){
                numCard += 1;
            }
        });
        return numCard;
    },


    getSyncData: function() {
        return this.pokers;
    },


    clear: function() {
        this.pokers = [];
    },
};

/**
 * 扑克房间
 * @param roomId        房间号
 * @param creatorId     创建者编号
 * @param args          参数
 * @constructor
 */
function Room(roomId, creatorId, args) {
    this.id = roomId;                   // 房间编号
    this.creator = creatorId;           // 创建者编号
    this.game = {};
    this.subGame = null;                // 子逻辑
    this.state = ROOM_STATE_WAITING;    // 房间状态
    this.newStates = [];                // 房间要切换到的状态
    this.stateSwitching = false;        // 房间正在切换

    this.roomPokers = new roomPokers(this);     // 桌面牌

    this.roundInfo = {                  // 当前轮游戏数据
        round           : 0,            // 当前是第几轮
        dealIndex       : 0,            // 发牌索引
        curPlay         : 1,            // 当前出牌玩家
        isFristCard     : true,         // 当前局是不是第一次出牌
        isNoCard        : false,        // 当前局是否有玩家出完牌
        noCardPlayersUid   : -1,         // 本轮牌玩家UIDs
        curPokers       : {},           // 当前出的牌
        curGameMark     : [],            // 当前局报牌标志
        markPlayerIndex : [],            // 当前局报牌人下标
    };

    this.players = {                    // 玩家
        1 : new LaomaziPlayer(this),
        2 : new LaomaziPlayer(this),
        3 : new LaomaziPlayer(this),
    };
    this.joinedPlayers = 0;             // 当前房间人数
    this.readyPlayers = 0;              // 准备就绪的人数
    this.disconnectedPlayerNum = 0;     // 掉线人数
    this.isDestroyed = false;           // 房间是否被销毁
    this.isKaiJu    = false;            // 是否已经退出房间
    //>> 申请解散房间
    this.isReqForDestroy = false;       // 正在请求销毁
    this.acceptDestroyPlayers = [];     // 确认销毁的玩家
    this.destroyTime = 0;               // 自动销毁时间
    this.isSureToDestroy = false;       // 确认房间销毁

    // 初始化数据
    this.init(args);
};


Room.prototype = {

    init: function(args) {
        this.game = {                         // 游戏信息
            type: args.type,                 // 类型
            multiple: 1,                    // 番数
            baseScore: 1,                  // 底分
            totalRound: 4,                // 总轮数
        };

        this.subGame = createSubGame(this.game.type, this);
        if (!this.subGame) {
            throw "NO SUCH SUB GAME";
        }
    },

    isFull : function () {
        return this.joinedPlayers == ROOMMAXPALYER;
    },
    isDestroy: function() {
        return this.isDestroyed;
    },

    isPlayerInRoom: function(uid) {
        for (var pos in this.players) {
            if (!this.players.hasOwnProperty(pos)) {
                continue;
            }

            if (this.players[pos].isPlayer(uid)) {
                return true;
            }
        }

        return false;
    },

    enumerationPlayer: function(handler) {
        for (var key in this.players) {
            if (!this.players.hasOwnProperty(key)) {
                continue;
            }

            if (handler(+key, this.players[key]) === false) {
                break;
            }
        }
    },

    getPlayer: function(uid) {
        for (var key in this.players) {
            if (!this.players.hasOwnProperty(key)) {
                continue;
            }

            var player = this.players[key];
            if (player.isPlayer(uid)) {
                return +key;
            }
        }

        return 0;
    },

    findEmptyPos: function() {
        for (var key in this.players) {
            if (!this.players.hasOwnProperty(key)) {
                continue;
            }

            if (!this.players[key].isInited()) {
                return +key;
            }
        }
        return 0;
    },

    onPlayerDisconnect: function(player) {
        // 有人掉线
        this.disconnectedPlayerNum += 1;

        var playerIndex = this.getPlayer(player.uid);

        // 给其他玩家推送通知
        this.enumerationPlayer(function(ePlayerIdx, ePlayer){
            if (ePlayer.isPlayer(player.uid) || !ePlayer.isInited()) {
                return;
            }

            ePlayer.sendPacket('setPlayerOffline', {
                playerIndex: playerIndex
            });
        }.bind(this));
    },

    destroy: function(uid, callback) {
        if (this.creator != uid) {
            callback(ErrorCodes.ERROR_PLAYER_NOT_CREATOR);
            return;
        }
        if(this.isKaiJu){
            callback(ErrorCodes.ERROR_ROOM_STATE_ERROR);
            return;
        }
        this.isKaiJu    = false;
        // 房主只能在没有游戏时销毁房间
        if (this.state == ROOM_STATE_PLAYING || this.state == ROOM_STATE_SETTLEMEN) {
            callback(ErrorCodes.ERROR_ROOM_STATE_ERROR);
            return;
        }

        // 判断需不需要保存战报
        if (this.state == ROOM_STATE_PLAYING || this.state == ROOM_STATE_SETTLEMEN) {
            this.onRoomFinish();
        }

        this.onDestroy();
        callback();
    },
    onDestroy: function() {
        // 广播房间被销毁通知
        this.boradcastMessage('setRoomDestroy', {});

        // 标记房间已经销毁
        this.isDestroyed = true;

        var playerUids = [];
        this.enumerationPlayer(function (ePlayerIdx, ePlayer) {
            if (ePlayer.isInited()) {
                playerUids.push(ePlayer.uid);
            }
        });

        this.players = null;
        this.roundInfo = null;

        // 通知游戏服务器该房间已经销毁
        requestGame(this.creator, {
            playerUids: playerUids,
        }, 'laomazi', 'roomDestroyed', function(resp){
            DEBUG(resp.desc);
        });
    },

    timerSendSettlementInfo:function(uid){
        var room = this;
        var curPlayer = null;
        var playerIdx = this.getPlayer(uid);
        var playCardPlayerIdx = this.getPlayer(this.roundInfo.noCardPlayersUid);
        // 发送结算结果
        var settlementRes = {
            isLastRound: (room.game.totalRound == room.roundInfo.round),
            totalRound: room.game.totalRound,             // 游戏总轮数
            round: room.roundInfo.round,                  // 游戏当前轮数
            curPlay: room.roundInfo.curPlay,              // 当前出牌的人
            curPokers: room.roundInfo.curPokers,                                // 当前出的牌
            playerIndex: playerIdx,                      // 玩家位置
            playCardPlayerIndex: playCardPlayerIdx,                       // 当前出牌人的位置
            isTheOwner: (room.creator == uid),
            isFrist: this.roundInfo.isFristCard,          // 当前局是否是第一次出牌，
            players: {},
        };
        room.enumerationPlayer(function(ePlayerIdx, ePlayer){
            settlementRes.players[ePlayerIdx] = ePlayer.getSettlementInfo(room.creator);
            if(ePlayer.uid == uid){
                curPlayer = ePlayer;
            }
        });

        if(!settlementRes){
            settlementRes = null;
        }
        curPlayer.sendPacket('setSettlement', settlementRes);
    },

    timerSendPlayerMark: function (  ) {
        var _me = this;
        var index = 0;
        _me.roundInfo.curGameMark.forEach( function ( mark ) {
            _me.boradcastMessage( 'setPlayerMark', {
                mark : mark,
                playerIndex : _me.roundInfo.markPlayerIndex[index],
            } );
            ++index;
        } );
    },
    
    getReqForDestroyInfo: function (  ) {
        var info = {};
        var repPlayerIndex = this.getPlayer(this.acceptDestroyPlayers[0]);
        var repPlayer = this.players[repPlayerIndex];
        info["repPlayer"] = repPlayer.player.name;
        var OkIdx = [];
        for (var key in this.acceptDestroyPlayers){
            if(this.acceptDestroyPlayers[key]){
                key = +key;
                if(key == 0){
                    continue;
                }
                var index = this.getPlayer(this.acceptDestroyPlayers[key]);
                var player = this.players[index];
                if(player){
                    OkIdx.push({index:index, name:player.player.name});
                }
            }
        }
        info["okIdx"] = OkIdx;
        return info;
    },
    /**
     * 将玩家加入房间
     * @param conn          // 连接对象
     * @param uid           // 玩家UID
     * @param player        // 玩家数据
     * @param callback
     */
    addPlayer: function(conn, uid, player, callback) {
        // 判断玩家是否已经在房间里面
        var room = this;
        var mPlayerIdx = this.getPlayer(uid);
        if (mPlayerIdx != 0) {
            var mPlayer = this.players[ mPlayerIdx ];
            if ( mPlayer.isOnline() && mPlayer.conn) {
                mPlayer.conn.close();
                mPlayer.conn = null;
                mPlayer.conn = conn;
            }
            // 玩家断线重连
            mPlayer.init( conn, uid, player );

            // 同步数据
            var syncData = null;
            if ( this.state == ROOM_STATE_SETTLEMEN ) {
                // 房间正在结算切玩家已经就绪
                syncData = {
                    totalRound : room.game.totalRound,             // 游戏总轮数
                    round : room.roundInfo.round,                  // 游戏当前轮数
                    curPlay : room.roundInfo.curPlay,              // 当前出牌的人
                    curPokers : [],                                // 当前出的牌
                    playerIndex : mPlayerIdx,                      // 玩家位置
                    playCardPlayerIndex : 0,                       // 当前出牌人的位置
                    isRuleOptional : room.isRuleOptional,
                    isTheOwner : (room.creator == uid),
                    isFrist : room.roundInfo.isFristCard,          // 当前局是否是第一次出牌，
                    players : {},
                };
                this.enumerationPlayer( function ( ePlayerIdx, ePlayer ) {
                    var userInfo = ePlayer.getSyncData( false );
                    syncData.players[ +ePlayerIdx ] = userInfo;

                    // 过滤数据
                    if ( !ePlayer.isPlayer( uid ) ) {
                        userInfo.cards = [];
                        userInfo.card = {};
                    }
                } );
            } else {
                syncData = {
                    totalRound : this.game.totalRound,             // 游戏总轮数
                    round : this.roundInfo.round,                  // 游戏当前轮数
                    curPlay : this.roundInfo.curPlay,              // 当前出牌的人
                    curPokers : this.roundInfo.curPokers,          // 当前出的牌
                    playCardPlayerIndex : this.getPlayer( this.roundInfo.noCardPlayersUid ),//当前出牌人的位置
                    isTheOwner : (room.creator == uid),
                    playerIndex : mPlayerIdx,                      // 玩家位置
                    isFrist : this.roundInfo.isFristCard,          // 当前局是否是第一次出牌，
                    players : {},
                };
                this.enumerationPlayer( function ( ePlayerIdx, ePlayer ) {
                    var flag1 = false;
                    // 过滤数据
                    if ( ePlayer.uid == uid ) {
                        flag1 = true;
                    }
                    var userInfo = ePlayer.getSyncData( flag1 );
                    syncData.players[ +ePlayerIdx ] = userInfo;
                } );
            }
            mPlayer.sendPacket( 'setPlayerReconnectInfo', syncData );
            mPlayer.onReconnect();

            // 广播玩家上线消息
            this.boradcastMessage( 'setPlayerOnline', {
                playerIndex : mPlayerIdx
            } );
            // 修改房间状态
            this.disconnectedPlayerNum -= 1;
            // 先回调加房间消息
            callback();

            if(this.isReqForDestroy){
                // 重连上来，正好解散状态
                setTimeout( function () {
                    mPlayer.sendPacket("reqForDestroyInfo",room.getReqForDestroyInfo());
                }, 200 * 1 );
            }else if ( room.state == ROOM_STATE_SETTLEMEN ) {
                // 重连上来，正好在结算状态
                setTimeout( function () {
                    room.timerSendSettlementInfo( mPlayer.uid );
                }, 200 * 1 );
            } else {
                if ( room.roundInfo.curGameMark && room.roundInfo.markPlayerIndex ) {
                    setTimeout( function () {
                        room.timerSendPlayerMark( mPlayer.uid );
                    }, 200 * 1 );
                }
            }
            return;
        }

        // 找到空闲位置
        var playerIndex = this.findEmptyPos();
        if (playerIndex == 0) {
            callback(ErrorCodes.ERROR_INTERNAL_ERROR);
            return;
        }

        // 将这个玩家关联到房间
        var newPlayer = this.players[playerIndex];
        newPlayer.init(conn, uid, player);
        this.joinedPlayers += 1;

        LOG(util.format('PLAYER %s JOINED ROOM %d - %d', player.name, this.id, Date.getStamp()));

        // 广播有人加入房间消息
        var newPlayerInfo = newPlayer.getInfo();
        this.boradcastMessage('setNewPlayer', {
            playerIndex: playerIndex,
            playerInfo: newPlayerInfo,
        },[playerIndex]);

        this.subGame.onPlayerJoinedRoom(playerIndex, newPlayer);

        // 将房间的一些状态数据发给玩家
        var roomInfo = {
            //round: this.roundInfo.round,
            totalRound: this.game.totalRound,
            isTheOwner: (room.creator == uid),
            players: {},
        };
        for (var pos in this.players) {
            if (!this.players.hasOwnProperty(pos)) {
                continue;
            }
            roomInfo.players[+pos] = this.players[pos].getInfo();
        }
        LOG("Room.addPlayer " + this.joinedPlayers);
        callback(null, roomInfo);
    },

    playerReady: function ( uid, callback ) {
        var _me = this;
        if (_me.state != ROOM_STATE_WAITING) {
            callback(ErrorCodes.ERROR_ROOM_STATE_ERROR);
            return;
        }
        // 检查玩家是否在本房间
        var playerIndex = _me.getPlayer(uid);
        if (playerIndex == 0) {
            callback(ErrorCodes.ERROR_PLAYER_NOT_IN_ROOM);
            return;
        }

        this.readyPlayers += 1;
        // 检查房间
        LOG("Room.readyPlayers " + this.readyPlayers);
        if (this.readyPlayers == ROOMMAXPALYER) {
            // 房间就绪，可以开始游戏
            this.pushNewState(ROOM_STATE_READY);
        }
        callback();
    },
    
    playCard: function(uid, cards, callback) {
        var _me = this;
        if (_me.state != ROOM_STATE_PLAYING) {
            callback(ErrorCodes.ERROR_ROOM_STATE_ERROR);
            return;
        }
        // 检查玩家是否在本房间
        var playerIndex = _me.getPlayer(uid);
        if (playerIndex == 0) {
            callback(ErrorCodes.ERROR_PLAYER_NOT_IN_ROOM);
            return;
        }
        var curPlayer = _me.players[playerIndex];

        // 检查是否该这个玩家出牌
        if (_me.roundInfo.curPlay != playerIndex) {
            callback(ErrorCodes.ERROR_NOT_PLAYER_ROUND);
            return;
        }

        var cardType = 0;

        //  检查玩家出的牌是否符合规则
        cardType = mFunc.checkCardType(curPlayer.handsPokers.getRemainCardNum() == 3, cards );
        if ( !cardType ) {
            callback( ErrorCodes.ERROR_PLAYER_PLAY_CARD_ERR );
            return;
        }

        // 出的牌是炸弹， 并且玩家标记了不能出炸弹，返回错误
        if( cardType == mjMark.PLAY_CARD_TYPE_BOMB && curPlayer.getNotUseBomb() && curPlayer.handsPokers.getRemainCardNum() != 3){
            callback(ErrorCodes.ERROR_PLAYER_NOT_PLAY_BOMB);
            return;
        }

        // 当前局是否第一次出牌，
        if(_me.roundInfo.isFristCard){
            // 检查出的牌中有没有红桃3，
            var cardredThreeNum = mFunc.checkfristCard(cards);
            if(!cardredThreeNum){
                callback(ErrorCodes.ERROR_PLAYER_PLAY_FRIST_CARD_ERR);
                return;
            }

            // 检查当前玩家有没有4个3 天炸
            var threeNum = mFunc.checkfristCard(curPlayer.handsPokers);
            if( threeNum == 4 && cardredThreeNum < 4){
                callback(ErrorCodes.ERROR_PLAYER_NOT_PLAY_DAYS_FRIED);
                return;
            }
            // 这个人出牌
            if (!curPlayer.playCard(cards)) {
                callback(ErrorCodes.ERROR_PLAYER_PLAY_CARD_FAILED);
                return;
            }
            // 四个3，炸弹
            if(cardredThreeNum == 4){
                curPlayer.setPushMarks(mjMark.PLAY_MARK_BOMB);
            }
            // 玩家出的牌符合规则， 更新房间内不是第一次出牌
            _me.roundInfo.isFristCard = false;
            // 更新当前房间出的牌
            _me.roundInfo.curPokers = cards;
            _me.roundInfo.noCardPlayersUid = uid;
            // 广播出牌消息
            _me.boradcastMessage('setPlayedCard', {
                cards: _me.roundInfo.curPokers.cards,
                num: _me.roundInfo.curPokers.num,
                playerIndex: playerIndex,
                playCardType:cardType,
            });

            // 一方玩家手牌已出完，游戏进入结算
            var numCard = curPlayer.handsPokers.getRemainCardNum();
            if( numCard == 0 ){
                if( cardType == mjMark.PLAY_CARD_TYPE_BOMB  && _me.roundInfo.noCardPlayersUid != uid && !curPlayer.getIsNullBomb()){
                    curPlayer.setPushMarks(mjMark.PLAY_CARD_TYPE_BOMB);
                }
                _me.roundInfo.isNoCard = true;
                _me.setRoomSettlementState();
                callback();
                return;
            }else if(numCard > 0 && numCard < 3) { // 检查玩家有没有报单报双
                // 发送玩家报牌消息
                var mark = (numCard == 1 )? mjMark.PLAY_MARK_BAO_SINGLE : mjMark.PLAY_MARK_BAO_DOUBLE;
                _me.roundInfo.curGameMark.push(mark);
                _me.roundInfo.markPlayerIndex.push(playerIndex);
                _me.boradcastMessage('setPlayerMark', {
                    mark: mark,
                    playerIndex: playerIndex
                });
            }
            _me.sendPlayCardPlayer();
            callback();
            return;
        }

        // 上一次出牌不是自己，检查 能否吃牌
        if (_me.roundInfo.noCardPlayersUid != uid) {
            // 不能吃牌，返回错误
            if ( !mFunc.checkIsCanEatCard(cards, _me.roundInfo.curPokers )){
                callback( ErrorCodes.ERROR_PLAYER_PLAY_CARD_ERR );
                return;
            }
            // 清除空炸
            curPlayer.setIsNullBomb( false );
        }else{
            // 上一次出牌的是自己，检查 是否是炸弹，是炸弹给当前玩家加炸弹标志
            if( mFunc.checkCardType(false, _me.roundInfo.curPokers) == mjMark.PLAY_CARD_TYPE_BOMB && !curPlayer.getIsNullBomb()){
                curPlayer.setPushMarks(mjMark.PLAY_CARD_TYPE_BOMB);
            }
            // 上一次出牌的是自己，当前出的牌也是炸弹，为空炸
            if(cardType == mjMark.PLAY_CARD_TYPE_BOMB){
                curPlayer.setIsNullBomb(true);
            }
        }

        // 检查放水
        var nextIndex = playerIndex + 1 > _me.joinedPlayers ? 1 : playerIndex + 1;
        var nextPlayer = _me.players[ nextIndex ];
        mFunc.checkPlayerIsDischargeWater(curPlayer, nextPlayer, cards, cardType);


        // 这个人出牌
        if (!curPlayer.playCard(cards)) {
            callback(ErrorCodes.ERROR_PLAYER_PLAY_CARD_FAILED);
            return;
        }

        _me.roundInfo.curPokers = cards;

        // 广播出牌消息
        _me.boradcastMessage('setPlayedCard', {
            cards: _me.roundInfo.curPokers.cards,
            num: _me.roundInfo.curPokers.num,
            playerIndex: playerIndex,
            playCardType:cardType,
        });

        // 一方玩家手牌已出完，游戏进入结算
        var numCard = curPlayer.handsPokers.getRemainCardNum();
        if( numCard == 0 ){
            // 最后一手是炸弹，                             不是空炸
            if( cardType == mjMark.PLAY_CARD_TYPE_BOMB && _me.roundInfo.noCardPlayersUid != uid && !curPlayer.getIsNullBomb() && !curPlayer.getNotUseBomb()){
                curPlayer.setPushMarks(mjMark.PLAY_CARD_TYPE_BOMB);
            }
            _me.roundInfo.isNoCard = true;
            _me.setRoomSettlementState();
            callback();
            return;
        }else if(numCard > 0 && numCard < 3) { // 检查玩家有没有报单报双
            // 发送玩家报牌消息
            var mark = (numCard == 1 )? mjMark.PLAY_MARK_BAO_SINGLE : mjMark.PLAY_MARK_BAO_DOUBLE;
            _me.roundInfo.curGameMark.push(mark);
            _me.roundInfo.markPlayerIndex.push(playerIndex);
            _me.boradcastMessage('setPlayerMark', {
                mark: mark,
                playerIndex: playerIndex
            });
        }

        _me.roundInfo.noCardPlayersUid = uid;

        // 通知客户端该谁出牌
        _me.sendPlayCardPlayer();
        callback();
    },


    // 并通知客户端该谁出牌
    sendPlayCardPlayer: function(pos) {
        pos = pos || (this.roundInfo.curPlay + 1);
        this.roundInfo.curPlay = pos;
        if (this.roundInfo.curPlay > this.joinedPlayers) {
            this.roundInfo.curPlay = 1;
        }
        this.boradcastMessage('setPlayCardPlayer', {
            playerIndex: this.roundInfo.curPlay,
            isFrist: this.roundInfo.isFristCard
        });
    },

    pass: function(uid, callback) {
        var _me = this;
        if (this.state != ROOM_STATE_PLAYING) {
            callback(ErrorCodes.ERROR_ROOM_STATE_ERROR);
            return;
        }

        // 检查玩家是否在本房间
        var playerIndex = _me.getPlayer(uid);
        if (playerIndex == 0) {
            callback(ErrorCodes.ERROR_PLAYER_NOT_IN_ROOM);
        }
        var curPlayer = _me.players[playerIndex];

        // 检查房间出牌中的 K，   检查当前玩家手中是否有相同数量的 A，出牌失败，有相同数量的 A 必须吃
        var isNum = mFunc.checkPokersIsK(_me.roundInfo.curPokers);
        if(isNum > 0 && isNum < 3 && mFunc.checkPlayerPokersIsOneA(curPlayer.handsPokers, isNum)){
            callback(ErrorCodes.ERROR_PLAYER_PLAY_CARD_FAILED);
            return;
        }

        // 检查房间出牌中的 A，并且只有一张，                 检查当前玩家手中是否有相同数量的  2, 出牌失败，必须出 2
        isNum = mFunc.checkPokersIsA(_me.roundInfo.curPokers);
        if(isNum == 1 && mFunc.checkPlayerPokersIsOne2(curPlayer.handsPokers)){
            callback(ErrorCodes.ERROR_PLAYER_PLAY_CARD_FAILED);
            return;
        }

        // 检查当前局上一次出的牌中是否只有一张 2
        isNum = mFunc.checkPokersIsOne2(_me.roundInfo.curPokers);
        // 当前玩家手中有炸弹没有吃，以后都不能使用炸弹了，只能拆开使用
        if (isNum == 1 && mFunc.checkPlayerPokersIsBomb(curPlayer.handsPokers)) {
            curPlayer.setNotUseBomb(true);
        }

        // 检查放水
        var nextIndex = playerIndex + 1 > this.joinedPlayers ? 1 : playerIndex + 1;
        var nextPlayer = this.players[ nextIndex ];
        mFunc.checkPassIsDischargeWater(curPlayer, nextPlayer, this.roundInfo.curPokers, mFunc.checkCardType(false, this.roundInfo.curPokers));

        // 下一个玩家的索引等于出牌玩家的索引，表示没有人压牌，清除玩家身上的作弊标志
        var nextPlayIdx = _me.roundInfo.curPlay + 1 > _me.joinedPlayers ? 1 : _me.roundInfo.curPlay + 1;
        if(nextPlayIdx == this.getPlayer(_me.roundInfo.noCardPlayersUid)) {
            _me.enumerationPlayer( function ( ePlayerIdx, ePlayer ) {
                if ( _me.roundInfo.noCardPlayersUid == ePlayer.uid ) {
                    ePlayer.setPlayerIsDischargeWater(false);
                    return;
                }
            } );
        }
        _me.boradcastMessage('setPlayedCard', {
            cards: null,
            playerIndex: playerIndex,
        });
        _me.sendPlayCardPlayer(0);
        callback && callback();
    },

    continue: function(uid, callback) {
        if (this.state != ROOM_STATE_SETTLEMEN) {
            callback(ErrorCodes.ERROR_ROOM_STATE_ERROR);
            return;
        }

        // 检查玩家是否在本房间
        var playerIndex = this.getPlayer(uid);
        if (playerIndex == 0) {
            callback(ErrorCodes.ERROR_PLAYER_NOT_IN_ROOM);
        }
        var curPlayer = this.players[playerIndex];

        curPlayer.continue();
        // 广播房间就绪
        this.boradcastMessage('setPlayerReady', {
            playerIndex: playerIndex,
        });

        this.readyPlayers += 1;
        if (this.readyPlayers == this.joinedPlayers) {
            // 开始下一局游戏
            this.pushNewState(ROOM_STATE_PLAYING);
        }
        callback();
    },

    sendTipMsg: function(uid, msgId, msg, callback) {
        //if (this.state != ROOM_STATE_SETTLEMEN) {
        //    callback(ErrorCodes.ERROR_ROOM_STATE_ERROR);
        //    return;
        //}

        // 检查玩家是否在本房间
        var playerIndex = this.getPlayer(uid);
        if (playerIndex == 0) {
            callback(ErrorCodes.ERROR_PLAYER_NOT_IN_ROOM);
        }

        this.boradcastMessage('setTipMsg', {
            playerIndex: playerIndex,
            msgId: msgId,
            msg: msg,
        },[playerIndex]);
    },

    update: function() {
        // 房间已经销毁
        if (this.isDestroyed) {
            return true;
        }

        // 正在切换状态
        if (this.stateSwitching) {
            return;
        }

        // 倒计时销毁房间
        if (this.isReqForDestroy && (Date.getStamp() >= this.destroyTime)) {
            this.isSureToDestroy = true;
            this.roundInfo.round = this.game.totalRound;

            this.pushNewState(ROOM_STATE_SETTLEMEN);
        }

        // 切换状态
        if (this.newStates.length != 0) {
            var toState = this.newStates.splice(0, 1);
            this.switchState(toState[0]);
        }
    },

    /**
     * 结算当前局
     */
    settlementCurrentGame: function () {
        this.readyPlayers = 0;
        //if(this.roundInfo.isNoCard) {
            this.subGame.onSettlementCurrentGame();
        //}
        // 所有轮结束或者房间已经确认要解散

        if ((this.game.totalRound == this.roundInfo.round) || this.isSureToDestroy) {
            this.onRoomFinish();
            // 是总结算清空房间内玩家，不给玩家推房间销毁消息
            setTimeout(function (  ) {
                if ( this.isKaiJu ) {
                    this.enumerationPlayer( function ( ePlayerIdx, ePlayer ) {
                        if ( ePlayer.uid != 0 && ePlayer.conn ) {
                            ePlayer.conn.close();
                            ePlayer.conn = null;
                        }
                    } );
                    this.players = null;
                    this.joinedPlayers = 0;
                    this.readyPlayers = 0;
                    this.roundInfo = null;
                }
                this.onDestroy();
            }.bind(this), 1000*3);
        }
    },

    onRoomFinish: function() {
        // 通知游戏服务器该房间已经结束
        var playersInfo = {};
        this.enumerationPlayer(function (ePlayerIdx, ePlayer) {
            if(ePlayer.uid) {
                playersInfo[ ePlayer.uid ] = {
                    integral : ePlayer.integral,
                    name : ePlayer.player.name,
                };

                requestGame( ePlayer.uid, {
                    isWin : (ePlayer.integral > 0 ? 1 : 0),
                }, 'laomazi', 'addNumberGames', function ( resp ) {
                    DEBUG( resp.desc );
                } );
            }
        });

        requestGame(this.creator, {
            roomId: this.id + 100000,
            time: Date.getStamp(),
            players: playersInfo,
        }, 'laomazi', 'roomFinished', function(resp){
            DEBUG(resp.desc);
        });
    },

    reqDestroyRoom: function(uid, callback) {
        if (this.isReqForDestroy) {
            callback(ErrorCodes.ERROR_ROOM_ALREADY_REQD_DESTROY);
            return;
        }

        // 检查玩家是否在本房间
        var playerIndex = this.getPlayer(uid);
        if (playerIndex == 0) {
            callback(ErrorCodes.ERROR_PLAYER_NOT_IN_ROOM);
        }

        this.isReqForDestroy = true;                // 设置标记
        this.destroyTime = Date.getStamp() + 300;   // 自动销毁倒计时

        this.acceptDestroyPlayers = [];
        this.acceptDestroyPlayers.push(uid);

        this.boradcastMessage('setRoomReqForDestroy', {
            playerIndex: playerIndex,
            time: this.destroyTime,
        });

        if(this.joinedPlayers == 1){
            this.boradcastMessage('setPlayerRespRoomReqForDestroy', {
                playerIndex: playerIndex,
                ok: true,
            });
            this.isSureToDestroy = true;

            this.roundInfo.isNoCard = false;

            this.roundInfo.round = this.game.totalRound;
            this.setRoomSettlementState();
        }
        callback();
    },

    respDestroyRoom: function(uid, ok, callback) {
        if (!this.isReqForDestroy) {
            callback(ErrorCodes.ERROR_ROOM_NOT_REQD_DESTROY);
            return;
        }

        /*if (this.state != ROOM_STATE_PLAYING) {
            callback(ErrorCodes.ERROR_ROOM_STATE_ERROR);
            return;
        }
*/
        // 检查玩家是否在本房间
        var playerIndex = this.getPlayer(uid);
        if (playerIndex == 0) {
            callback(ErrorCodes.ERROR_PLAYER_NOT_IN_ROOM);
            return;
        }

        if (this.acceptDestroyPlayers.indexOf(uid) != -1) {
            callback(ErrorCodes.ERROR_PLAYER_ALREADY_ACCEPT);
            return;
        }
        this.boradcastMessage('setPlayerRespRoomReqForDestroy', {
            playerIndex: playerIndex,
            ok: ok,
        });
        if (!ok) {
            // 有玩家拒绝，取消销毁房间
            this.isReqForDestroy = false;
            this.destroyTime = 0;
        } else {
            // 该玩家同意销毁
            this.acceptDestroyPlayers.push(uid);

            if (this.acceptDestroyPlayers.length == (this.joinedPlayers - this.disconnectedPlayerNum)) {
                // 在线玩家都同意销毁，立即结算游戏
                this.isSureToDestroy = true;
                this.roundInfo.isNoCard = false;
                this.roundInfo.round = this.game.totalRound;
                this.setRoomSettlementState();
            }
        }
    },

    respExitRoom: function(uid, callback) {

        // 检查玩家是否在本房间
        var playerIndex = this.getPlayer(uid);
        if (playerIndex == 0) {
            callback(ErrorCodes.ERROR_PLAYER_NOT_IN_ROOM);
            return;
        }

        if (this.isKaiJu ) {
            callback(ErrorCodes.ERROR_ROOM_STATE_ERROR);
            return;
        }
        // 玩家退出房间
        var curPlayer = this.players[playerIndex];

        // 通知游戏服务器该这个玩家滚蛋
        requestGame(curPlayer.uid, {}, 'laomazi', 'playerExitRoom', function(resp){
            DEBUG(resp.desc);
        });

        // 这个玩家滚蛋
        curPlayer.sendPacket('thisExitRoom',{});
        curPlayer.exit();
        // 通知其他人这个SB滚蛋了


        this.boradcastMessage('setPlayerExitRoom', {
            playerIndex: playerIndex,
        },[playerIndex]);

        this.joinedPlayers -= 1;
        this.readyPlayers -= 1;
    },

    ///////////////////////////////////////////////////////////////////////////
    //>> 功能函数

    // 广播消息
    boradcastMessage: function(act, msg, exclude) {
        exclude = exclude || [];
        for (var key in this.players) {
            if (!this.players.hasOwnProperty(key)) {
                continue;
            }

            if (exclude.indexOf(+key) != -1) {
                continue;
            }

            if (this.players[key].isInited()) {
                this.players[key].sendPacket(act, msg);
            }
        }
    },

    pushNewState: function(state) {
        this.newStates.push(state);
    },

    /**
     * 设置房间为结算状态
     * @param
     */
    setRoomSettlementState: function () {
        this.pushNewState(ROOM_STATE_SETTLEMEN);
    },
    /**
     * 扣除房主房卡
     * @returns {boolean}
     */
    buckleOwnrCard: function() {
        var _me = this;
        var flag = true;
        if ( _me.creator ) {
            var cardNeed = 1;
            requestGame( _me.creator, {
                ownrKey : "card",
                cardNum : -cardNeed,
            }, 'laomazi', 'addPlayerStats', function ( resp ) {
                if ( resp.code == 0 ) {
                    DEBUG( resp.desc );
                } else {
                    flag = false;
                    return;
                }
            } );
        }
        return flag;
    },

    clearTempDate: function (  ) {
        var roundInfo = this.roundInfo;
        // 增加轮数
        roundInfo.round += 1;
        // 发牌索引置零
        roundInfo.dealIndex = 0
        roundInfo.curPokers = {};
        roundInfo.curPlay         = 0;            // 当前出牌玩家
        roundInfo.isFristCard     = true,         // 当前局是不是第一次出牌
        roundInfo.noCardPlayersUid   = -1;         // 本轮牌玩家UIDs
        roundInfo.curPokers       = {};           // 当前出的牌
        roundInfo.curGameMark     = [];            // 当前局报牌标志
        roundInfo.markPlayerIndex = [];            // 当前局报牌人下标
    },

    // 房间状态切换
    switchState: function(newState) {
        this.stateSwitching = true;
        LOG('TRY SWITCH TO ' + newState);

        var _me = this;
        async.series([function(cb){
            // 切出当前状态
            cb();
        }, function(cb){
            // 切入新状态
            switch (newState) {
                case ROOM_STATE_READY:
                    // 直接跳到游戏开始
                    _me.isKaiJu = true;
                    if(_me.buckleOwnrCard()){
                        _me.pushNewState(ROOM_STATE_PLAYING);
                    }else{
                        LOG('BUCKLE OWNR CARD FAILED');
                    }
                    break;
                case ROOM_STATE_PLAYING:

                    _me.clearTempDate();

                    // 清空玩家身上相关打牌数据,防止重连未点继续游戏
                    _me.enumerationPlayer(function ( ePlayerIdx, ePlayer ) {
                        if(ePlayer.uid){
                            ePlayer.continue();
                        }
                    });
                    _me.subGame.onInit(_me.roundInfo.round == 1);

                    async.series([function(cb2){
                        // 发送房间信息
                        _me.boradcastMessage('setRoomInfo', {
                            round: _me.roundInfo.round,
                            totalRound : _me.game.totalRound
                        });
                        cb2();
                    },function(cb2){
                        // 发牌
                        // 给玩家发牌
                        var roomPokers = _me.roomPokers;
                        roomPokers.gen(_me.game.type);
                        _me.players[1].setCards(roomPokers.dealCards(16),1);
                        _me.players[2].setCards(roomPokers.dealCards(16),2);
                        _me.players[3].setCards(roomPokers.dealCards(16),3);

                        var firstCard = 1;
                        for(var key in _me.players){
                            if(!_me.players.hasOwnProperty(key)){
                                continue;
                            }
                            key = +key;
                            var curPlay = _me.players[key];
                            if(curPlay.handsPokers.hasSameColor({type: 3, value: 1})){
                                firstCard = key;
                                break;
                            }
                        }

                        _me.roundInfo.curPlay = firstCard;
                        _me.sendPlayCardPlayer(_me.roundInfo.curPlay);

                        cb2();
                    }], function(err){
                        cb(err);
                    });
                    return;
                case ROOM_STATE_SETTLEMEN:
                    _me.settlementCurrentGame();
                    break;
                default:
                    break;
            }
            cb();
        }], function(err){
            _me.state = newState;
            LOG('SWITCHED TO ' + newState);

            _me.stateSwitching = false;
        });
    }
};
exports.Room = Room;

///////////////////////////////////////////////////////////////////////////////
//>> 房间状态
var ROOM_STATE_WAITING  = 1;        // 等待玩家加入
var ROOM_STATE_READY    = 2;        // 等待房主开始游戏
var ROOM_STATE_PLAYING  = 3;        // 游戏中
var ROOM_STATE_SETTLEMEN= 4;        // 游戏结算中


///////////////////////////////////////////////////////////////////////////////
//>> 功能函数

function createSubGame(type, owner) {
    switch (type) {
        case "laomazi":
            return new subGame[type].SubGame(owner);
    }
    return null;
}
